//! # Kubernetes 配置管理
//!
//! 基于 ConfigMap 和 Secret 的配置管理功能。

use std::collections::HashMap;
use std::sync::Arc;
use async_trait::async_trait;
use futures::stream::StreamExt;
use kube::{
    Api, Client,
    runtime::{watcher, WatchStreamExt},
};
use k8s_openapi::api::core::v1::{ConfigMap, Secret};
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use tracing::{info, debug, warn, error};

use crate::client::KubernetesClient;
use crate::error::{K8sError, K8sResult};

/// 配置源类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConfigSource {
    /// ConfigMap 配置
    ConfigMap {
        namespace: String,
        name: String,
        key: Option<String>,
    },
    /// Secret 配置
    Secret {
        namespace: String,
        name: String,
        key: Option<String>,
    },
}

/// 配置项
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigItem {
    /// 配置键
    pub key: String,
    /// 配置值
    pub value: String,
    /// 配置源
    pub source: ConfigSource,
    /// 版本（资源版本）
    pub version: String,
}

/// 配置事件
#[derive(Debug, Clone)]
pub enum ConfigEvent {
    /// 配置添加
    Added(ConfigItem),
    /// 配置修改
    Modified(ConfigItem),
    /// 配置删除
    Deleted(ConfigItem),
}

/// 配置管理接口
#[async_trait]
pub trait ConfigManager: Send + Sync {
    /// 获取配置
    async fn get_config(&self, source: &ConfigSource) -> K8sResult<HashMap<String, String>>;
    
    /// 获取单个配置项
    async fn get_config_item(&self, source: &ConfigSource, key: &str) -> K8sResult<String>;
    
    /// 监听配置变化
    async fn watch_config<F>(&self, source: &ConfigSource, callback: F) -> K8sResult<()>
    where
        F: Fn(ConfigEvent) + Send + Sync + 'static;
        
    /// 更新配置
    async fn update_config(&self, source: &ConfigSource, data: HashMap<String, String>) -> K8sResult<()>;
}

/// Kubernetes 配置管理器
pub struct K8sConfigManager {
    /// Kubernetes 客户端
    client: Arc<KubernetesClient>,
    /// 配置缓存
    config_cache: Arc<RwLock<HashMap<String, ConfigItem>>>,
}

impl K8sConfigManager {
    /// 创建新的配置管理器
    pub fn new(client: Arc<KubernetesClient>) -> Self {
        Self {
            client,
            config_cache: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// 从 ConfigMap 获取配置
    async fn get_configmap_data(&self, namespace: &str, name: &str) -> K8sResult<HashMap<String, String>> {
        debug!("获取 ConfigMap {}/{}", namespace, name);

        let configmaps: Api<ConfigMap> = Api::namespaced(self.client.client().clone(), namespace);
        let configmap = configmaps.get(name).await
            .map_err(|e| K8sError::resource_not_found("ConfigMap", name, namespace))?;

        let btreemap = configmap.data.unwrap_or_default();
        let hashmap = btreemap.into_iter().collect();
        Ok(hashmap)
    }

    /// 从 Secret 获取配置
    async fn get_secret_data(&self, namespace: &str, name: &str) -> K8sResult<HashMap<String, String>> {
        debug!("获取 Secret {}/{}", namespace, name);

        let secrets: Api<Secret> = Api::namespaced(self.client.client().clone(), namespace);
        let secret = secrets.get(name).await
            .map_err(|e| K8sError::resource_not_found("Secret", name, namespace))?;

        let mut data = HashMap::new();
        if let Some(secret_data) = secret.data {
            for (key, value) in secret_data {
                // 解码 base64 数据
                let decoded = String::from_utf8(value.0)
                    .map_err(|e| K8sError::config_error(format!("Secret 数据解码失败: {}", e)))?;
                data.insert(key, decoded);
            }
        }

        Ok(data)
    }

    /// 更新 ConfigMap
    async fn update_configmap(&self, namespace: &str, name: &str, data: HashMap<String, String>) -> K8sResult<()> {
        debug!("更新 ConfigMap {}/{}", namespace, name);

        let configmaps: Api<ConfigMap> = Api::namespaced(self.client.client().clone(), namespace);
        
        // 获取现有的 ConfigMap
        let mut configmap = configmaps.get(name).await
            .map_err(|e| K8sError::resource_not_found("ConfigMap", name, namespace))?;

        // 更新数据
        let btreemap = data.into_iter().collect();
        configmap.data = Some(btreemap);

        // 应用更新
        configmaps.replace(name, &Default::default(), &configmap).await
            .map_err(|e| K8sError::config_error(format!("更新 ConfigMap 失败: {}", e)))?;

        info!("ConfigMap {}/{} 更新成功", namespace, name);
        Ok(())
    }

    /// 更新 Secret
    async fn update_secret(&self, namespace: &str, name: &str, data: HashMap<String, String>) -> K8sResult<()> {
        debug!("更新 Secret {}/{}", namespace, name);

        let secrets: Api<Secret> = Api::namespaced(self.client.client().clone(), namespace);
        
        // 获取现有的 Secret
        let mut secret = secrets.get(name).await
            .map_err(|e| K8sError::resource_not_found("Secret", name, namespace))?;

        // 编码数据为 base64
        let mut encoded_data = HashMap::new();
        for (key, value) in data {
            encoded_data.insert(key, k8s_openapi::ByteString(value.into_bytes()));
        }

        // 更新数据
        let btreemap = encoded_data.into_iter().collect();
        secret.data = Some(btreemap);

        // 应用更新
        secrets.replace(name, &Default::default(), &secret).await
            .map_err(|e| K8sError::config_error(format!("更新 Secret 失败: {}", e)))?;

        info!("Secret {}/{} 更新成功", namespace, name);
        Ok(())
    }

    /// 生成配置项的缓存键
    fn cache_key(source: &ConfigSource, key: &str) -> String {
        match source {
            ConfigSource::ConfigMap { namespace, name, .. } => {
                format!("configmap:{}:{}:{}", namespace, name, key)
            }
            ConfigSource::Secret { namespace, name, .. } => {
                format!("secret:{}:{}:{}", namespace, name, key)
            }
        }
    }
}

#[async_trait]
impl ConfigManager for K8sConfigManager {
    async fn get_config(&self, source: &ConfigSource) -> K8sResult<HashMap<String, String>> {
        match source {
            ConfigSource::ConfigMap { namespace, name, key } => {
                let data = self.get_configmap_data(namespace, name).await?;
                
                if let Some(specific_key) = key {
                    // 如果指定了特定键，只返回该键的值
                    let mut result = HashMap::new();
                    if let Some(value) = data.get(specific_key) {
                        result.insert(specific_key.clone(), value.clone());
                    }
                    Ok(result)
                } else {
                    // 返回所有数据
                    Ok(data)
                }
            }
            ConfigSource::Secret { namespace, name, key } => {
                let data = self.get_secret_data(namespace, name).await?;
                
                if let Some(specific_key) = key {
                    // 如果指定了特定键，只返回该键的值
                    let mut result = HashMap::new();
                    if let Some(value) = data.get(specific_key) {
                        result.insert(specific_key.clone(), value.clone());
                    }
                    Ok(result)
                } else {
                    // 返回所有数据
                    Ok(data)
                }
            }
        }
    }

    async fn get_config_item(&self, source: &ConfigSource, key: &str) -> K8sResult<String> {
        let data = self.get_config(source).await?;
        data.get(key)
            .cloned()
            .ok_or_else(|| K8sError::config_error(format!("配置键 '{}' 不存在", key)))
    }

    async fn watch_config<F>(&self, source: &ConfigSource, callback: F) -> K8sResult<()>
    where
        F: Fn(ConfigEvent) + Send + Sync + 'static
    {
        let callback = Arc::new(callback);

        match source {
            ConfigSource::ConfigMap { namespace, name, .. } => {
                info!("开始监听 ConfigMap {}/{} 的变化", namespace, name);

                let configmaps: Api<ConfigMap> = Api::namespaced(self.client.client().clone(), namespace);
                let watcher = watcher(configmaps, Default::default());

                let source_clone = source.clone();
                let callback_clone = callback.clone();

                tokio::spawn(async move {
                    let mut stream = watcher.boxed();
                    
                    while let Some(event) = stream.next().await {
                        match event {
                            Ok(watcher::Event::Applied(configmap)) => {
                                if let Some(data) = configmap.data {
                                    for (key, value) in data {
                                        let config_item = ConfigItem {
                                            key: key.clone(),
                                            value,
                                            source: source_clone.clone(),
                                            version: configmap.metadata.resource_version
                                                .clone().unwrap_or_default(),
                                        };
                                        callback_clone(ConfigEvent::Added(config_item));
                                    }
                                }
                            }
                            Ok(watcher::Event::Deleted(configmap)) => {
                                if let Some(data) = configmap.data {
                                    for (key, value) in data {
                                        let config_item = ConfigItem {
                                            key: key.clone(),
                                            value,
                                            source: source_clone.clone(),
                                            version: configmap.metadata.resource_version
                                                .clone().unwrap_or_default(),
                                        };
                                        callback_clone(ConfigEvent::Deleted(config_item));
                                    }
                                }
                            }
                            Err(e) => {
                                error!("ConfigMap 监听错误: {}", e);
                            }
                            _ => {}
                        }
                    }
                });
            }
            ConfigSource::Secret { namespace, name, .. } => {
                info!("开始监听 Secret {}/{} 的变化", namespace, name);

                let secrets: Api<Secret> = Api::namespaced(self.client.client().clone(), namespace);
                let watcher = watcher(secrets, Default::default());

                let source_clone = source.clone();
                
                tokio::spawn(async move {
                    let mut stream = watcher.boxed();
                    
                    while let Some(event) = stream.next().await {
                        match event {
                            Ok(watcher::Event::Applied(secret)) => {
                                if let Some(data) = secret.data {
                                    for (key, value) in data {
                                        if let Ok(decoded) = String::from_utf8(value.0) {
                                            let config_item = ConfigItem {
                                                key: key.clone(),
                                                value: decoded,
                                                source: source_clone.clone(),
                                                version: secret.metadata.resource_version
                                                    .clone().unwrap_or_default(),
                                            };
                                            callback(ConfigEvent::Added(config_item));
                                        }
                                    }
                                }
                            }
                            Ok(watcher::Event::Deleted(secret)) => {
                                if let Some(data) = secret.data {
                                    for (key, value) in data {
                                        if let Ok(decoded) = String::from_utf8(value.0) {
                                            let config_item = ConfigItem {
                                                key: key.clone(),
                                                value: decoded,
                                                source: source_clone.clone(),
                                                version: secret.metadata.resource_version
                                                    .clone().unwrap_or_default(),
                                            };
                                            callback(ConfigEvent::Deleted(config_item));
                                        }
                                    }
                                }
                            }
                            Err(e) => {
                                error!("Secret 监听错误: {}", e);
                            }
                            _ => {}
                        }
                    }
                });
            }
        }

        Ok(())
    }

    async fn update_config(&self, source: &ConfigSource, data: HashMap<String, String>) -> K8sResult<()> {
        match source {
            ConfigSource::ConfigMap { namespace, name, .. } => {
                self.update_configmap(namespace, name, data).await
            }
            ConfigSource::Secret { namespace, name, .. } => {
                self.update_secret(namespace, name, data).await
            }
        }
    }
}

/// 配置监听器
pub struct ConfigWatcher {
    /// 配置管理器
    config_manager: Arc<K8sConfigManager>,
}

impl ConfigWatcher {
    /// 创建新的配置监听器
    pub fn new(config_manager: Arc<K8sConfigManager>) -> Self {
        Self { config_manager }
    }

    /// 监听多个配置源
    pub async fn watch_multiple<F>(&self, sources: Vec<ConfigSource>, callback: F) -> K8sResult<()>
    where
        F: Fn(ConfigEvent) + Send + Sync + Clone + 'static
    {
        for source in sources {
            let callback_clone = callback.clone();
            self.config_manager.watch_config(&source, move |event| {
                callback_clone(event);
            }).await?;
        }
        Ok(())
    }
}

/// 配置构建器
pub struct ConfigBuilder {
    sources: Vec<ConfigSource>,
}

impl ConfigBuilder {
    /// 创建新的配置构建器
    pub fn new() -> Self {
        Self {
            sources: Vec::new(),
        }
    }

    /// 添加 ConfigMap 源
    pub fn add_configmap(mut self, namespace: &str, name: &str, key: Option<&str>) -> Self {
        self.sources.push(ConfigSource::ConfigMap {
            namespace: namespace.to_string(),
            name: name.to_string(),
            key: key.map(|k| k.to_string()),
        });
        self
    }

    /// 添加 Secret 源
    pub fn add_secret(mut self, namespace: &str, name: &str, key: Option<&str>) -> Self {
        self.sources.push(ConfigSource::Secret {
            namespace: namespace.to_string(),
            name: name.to_string(),
            key: key.map(|k| k.to_string()),
        });
        self
    }

    /// 构建配置映射
    pub async fn build(&self, config_manager: &K8sConfigManager) -> K8sResult<HashMap<String, String>> {
        let mut config = HashMap::new();

        for source in &self.sources {
            let source_config = config_manager.get_config(source).await?;
            config.extend(source_config);
        }

        Ok(config)
    }
}

impl Default for ConfigBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_source_serialization() {
        let source = ConfigSource::ConfigMap {
            namespace: "default".to_string(),
            name: "my-config".to_string(),
            key: Some("app.properties".to_string()),
        };

        let json = serde_json::to_string(&source).unwrap();
        let deserialized: ConfigSource = serde_json::from_str(&json).unwrap();
        
        match deserialized {
            ConfigSource::ConfigMap { namespace, name, key } => {
                assert_eq!(namespace, "default");
                assert_eq!(name, "my-config");
                assert_eq!(key, Some("app.properties".to_string()));
            }
            _ => panic!("Unexpected config source type"),
        }
    }

    #[test]
    fn test_config_builder() {
        let builder = ConfigBuilder::new()
            .add_configmap("default", "app-config", None)
            .add_secret("default", "app-secrets", Some("password"));

        assert_eq!(builder.sources.len(), 2);
    }

    #[test]
    fn test_cache_key_generation() {
        let source = ConfigSource::ConfigMap {
            namespace: "default".to_string(),
            name: "my-config".to_string(),
            key: None,
        };

        let key = K8sConfigManager::cache_key(&source, "app.port");
        assert_eq!(key, "configmap:default:my-config:app.port");
    }
}